查看原文
其他

【翻译】《利用Python进行数据分析·第2版》第14章(下)数据分析案例

SeanCheney Python爱好者社区 2019-04-07

作者:SeanCheney   Python爱好者社区专栏作者

简书专栏:https://www.jianshu.com/u/130f76596b02


前文传送门:

【翻译】《利用Python进行数据分析·第2版》第1章 准备工作

【翻译】《利用Python进行数据分析·第2版》第2章(上)Python语法基础,IPython和Jupyter

【翻译】《利用Python进行数据分析·第2版》第2章(中)Python语法基础,IPython和Jupyter

【翻译】《利用Python进行数据分析·第2版》第2章(下)Python语法基础,IPython和Jupyter

【翻译】《利用Python进行数据分析·第2版》第3章(上)Python的数据结构、函数和文件

【翻译】《利用Python进行数据分析·第2版》第3章(中)Python的数据结构、函数和文件

【翻译】《利用Python进行数据分析·第2版》第3章(下)Python的数据结构、函数和文件

【翻译】《利用Python进行数据分析·第2版》第4章(上)NumPy基础:数组和矢量计算

【翻译】《利用Python进行数据分析·第2版》第4章(中)NumPy基础:数组和矢量计算

【翻译】《利用Python进行数据分析·第2版》第4章(下)NumPy基础:数组和矢量计算

【翻译】《利用Python进行数据分析·第2版》第5章(上)pandas入门

【翻译】《利用Python进行数据分析·第2版》第5章(中)pandas入门

【翻译】《利用Python进行数据分析·第2版》第5章(下)pandas入门

【翻译】《利用Python进行数据分析·第2版》第6章(上) 数据加载、存储与文件格式

【翻译】《利用Python进行数据分析·第2版》第6章(中) 数据加载、存储与文件格式

【翻译】《利用Python进行数据分析·第2版》第6章(下) 数据加载、存储与文件格式

【翻译】《利用Python进行数据分析·第2版》第7章(上)数据清洗和准备

【翻译】《利用Python进行数据分析·第2版》第7章(中) 数据清洗和准备

【翻译】《利用Python进行数据分析·第2版》第7章(下) 数据清洗和准备

【翻译】《利用Python进行数据分析·第2版》第8章(上) 数据规整:聚合、合并和重塑

【翻译】《利用Python进行数据分析·第2版》第8章(中) 数据规整:聚合、合并和重塑

【翻译】《利用Python进行数据分析·第2版》第8章(下) 数据规整:聚合、合并和重塑

【翻译】《利用Python进行数据分析·第2版》第9章(上) 绘图和可视化

【翻译】《利用Python进行数据分析·第2版》第9章(中) 绘图和可视化

  【翻译】《利用Python进行数据分析·第2版》第9章(下) 绘图和可视化

  【翻译】《利用Python进行数据分析·第2版》第10章(上) 数据聚合与分组运算

  【翻译】《利用Python进行数据分析·第2版》第10章(中) 数据聚合与分组运算

  【翻译】《利用Python进行数据分析·第2版》第10章(下) 数据聚合与分组运算

  【翻译】《利用Python进行数据分析·第2版》第11章(上) 时间序列

  【翻译】《利用Python进行数据分析·第2版》第11章(中) 时间序列

  【翻译】《利用Python进行数据分析·第2版》第11章(中二) 时间序列

  【翻译】《利用Python进行数据分析·第2版》第11章(下) 时间序列

  【翻译】《利用Python进行数据分析·第2版》第12章(上) pandas高级应用

  【翻译】《利用Python进行数据分析·第2版》第12章(中) pandas高级应用

  【翻译】《利用Python进行数据分析·第2版》第12章(下) pandas高级应用

  【翻译】《利用Python进行数据分析·第2版》第13章(上) Python建模库介绍

  【翻译】《利用Python进行数据分析·第2版》第13章(中) Python建模库介绍

  【翻译】《利用Python进行数据分析·第2版》第13章(中二) Python建模库介绍

  【翻译】《利用Python进行数据分析·第2版》第13章(下) Python建模库介绍

  【翻译】《利用Python进行数据分析·第2版》第14章(上)数据分析案例

  【翻译】《利用Python进行数据分析·第2版》第14章(中)数据分析案例

  【翻译】《利用Python进行数据分析·第2版》第14章(中二)数据分析案例


14.4 USDA食品数据库


美国农业部(USDA)制作了一份有关食物营养信息的数据库。Ashley Williams制作了该数据的JSON版(http://ashleyw.co.uk/project/food-nutrient-database)。其中的记录如下所示:

{  "id": 21441,  "description": "KENTUCKY FRIED CHICKEN, Fried Chicken, EXTRA CRISPY, Wing, meat and skin with breading",  "tags": ["KFC"],  "manufacturer": "Kentucky Fried Chicken", "group": "Fast Foods",  "portions": [    {      "amount": 1,      "unit": "wing, with skin",      "grams": 68.0    },    ...  ],  "nutrients": [    {      "value": 20.8,      "units": "g",      "description": "Protein",      "group": "Composition"    },    ...  ] }

每种食物都带有若干标识性属性以及两个有关营养成分和分量的列表。这种形式的数据不是很适合分析工作,因此我们需要做一些规整化以使其具有更好用的形式。

从上面列举的那个网址下载并解压数据之后,你可以用任何喜欢的JSON库将其加载到Python中。我用的是Python内置的json模块:

In [154]: import json In [155]: db = json.load(open('datasets/usda_food/database.json')) In [156]: len(db) Out[156]: 6636

db中的每个条目都是一个含有某种食物全部数据的字典。nutrients字段是一个字典列表,其中的每个字典对应一种营养成分:

In [157]: db[0].keys() Out[157]: dict_keys(['id', 'description', 'tags', 'manufacturer', 'group', 'porti ons', 'nutrients']) In [158]: db[0]['nutrients'][0] Out[158]: {'description': 'Protein', 'group': 'Composition', 'units': 'g', 'value': 25.18} In [159]: nutrients = pd.DataFrame(db[0]['nutrients']) In [160]: nutrients[:7] Out[160]:                   description        group units    value 0                      Protein  Composition     g    25.18 1            Total lipid (fat)  Composition     g    29.20 2  Carbohydrate, by difference  Composition     g     3.06 3                          Ash        Other     g     3.28 4                       Energy       Energy  kcal   376.00 5                        Water  Composition     g    39.28 6                       Energy       Energy    kJ  1573.00

在将字典列表转换为DataFrame时,可以只抽取其中的一部分字段。这里,我们将取出食物的名称、分类、编号以及制造商等信息:

In [161]: info_keys = ['description', 'group', 'id', 'manufacturer'] In [162]: info = pd.DataFrame(db, columns=info_keys) In [163]: info[:5] Out[163]:                          description                   group    id  \ 0                     Cheese, caraway  Dairy and Egg Products  1008   1                     Cheese, cheddar  Dairy and Egg Products  1009 2                        Cheese, edam  Dairy and Egg Products  1018   3                        Cheese, feta  Dairy and Egg Products  1019   4  Cheese, mozzarella, part skim milk  Dairy and Egg Products  1028    manufacturer   0               1               2               3               4               In [164]: info.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 6636 entries, 0 to 6635 Data columns (total 4 columns): description     6636 non-null object group           6636 non-null object id              6636 non-null int64 manufacturer    5195 non-null object dtypes: int64(1), object(3) memory usage: 207.5+ KB

通过value_counts,你可以查看食物类别的分布情况:

In [165]: pd.value_counts(info.group)[:10] Out[165]: Vegetables and Vegetable Products    812 Beef Products                        618 Baked Products                       496 Breakfast Cereals                    403 Fast Foods                           365 Legumes and Legume Products          365 Lamb, Veal, and Game Products        345 Sweets                               341 Pork Products                        328 Fruits and Fruit Juices              328 Name: group, dtype: int64

现在,为了对全部营养数据做一些分析,最简单的办法是将所有食物的营养成分整合到一个大表中。我们分几个步骤来实现该目的。首先,将各食物的营养成分列表转换为一个DataFrame,并添加一个表示编号的列,然后将该DataFrame添加到一个列表中。最后通过concat将这些东西连接起来就可以了:


顺利的话,nutrients的结果是:

In [167]: nutrients Out[167]:                               description        group units    value     id 0                                  Protein  Composition     g   25.180   1008 1                        Total lipid (fat)  Composition     g   29.200   1008 2              Carbohydrate, by difference  Composition     g    3.060   1008 3                                      Ash        Other     g    3.280   1008 4                                   Energy       Energy  kcal  376.000   1008 ...                                    ...          ... ...      ...    ... 389350                 Vitamin B-12, added     Vitamins   mcg    0.000  43546 389351                         Cholesterol        Other    mg    0.000  43546 389352        Fatty acids, total saturated        Other     g    0.072  43546 389353  Fatty acids, total monounsaturated        Other     g    0.028  43546 389354  Fatty acids, total polyunsaturated        Other     g    0.041  43546 [389355 rows x 5 columns]

我发现这个DataFrame中无论如何都会有一些重复项,所以直接丢弃就可以了:

In [168]: nutrients.duplicated().sum()  # number of duplicates Out[168]: 14179 In [169]: nutrients = nutrients.drop_duplicates()

由于两个DataFrame对象中都有"group"和"description",所以为了明确到底谁是谁,我们需要对它们进行重命名:

In [170]: col_mapping = {'description' : 'food',   .....:                'group'       : 'fgroup'} In [171]: info = info.rename(columns=col_mapping, copy=False) In [172]: info.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 6636 entries, 0 to 6635 Data columns (total 4 columns): food            6636 non-null object fgroup          6636 non-null object id              6636 non-null int64 manufacturer    5195 non-null object dtypes: int64(1), object(3) memory usage: 207.5+ KB In [173]: col_mapping = {'description' : 'nutrient',   .....:                'group' : 'nutgroup'} In [174]: nutrients = nutrients.rename(columns=col_mapping, copy=False) In [175]: nutrients Out[175]:                                  nutrient     nutgroup units    value     id 0                                  Protein  Composition     g   25.180   1008 1                        Total lipid (fat)  Composition     g   29.200   1008 2              Carbohydrate, by difference  Composition     g    3.060   1008 3                                      Ash        Other     g    3.280   1008 4                                   Energy       Energy  kcal  376.000   1008 ...                                    ...          ...   ...      ...    ... 389350                 Vitamin B-12, added     Vitamins   mcg    0.000  43546 389351                         Cholesterol        Other    mg    0.000  43546 389352        Fatty acids, total saturated        Other     g    0.072  43546 389353  Fatty acids, total monounsaturated        Other     g    0.028  43546 389354  Fatty acids, total polyunsaturated        Other     g    0.041  43546 [375176 rows x 5 columns]

做完这些,就可以将info跟nutrients合并起来:

In [176]: ndata = pd.merge(nutrients, info, on='id', how='outer') In [177]: ndata.info() <class 'pandas.core.frame.DataFrame'> Int64Index: 375176 entries, 0 to 375175 Data columns (total 8 columns): nutrient        375176 non-null object nutgroup        375176 non-null object units           375176 non-null object value           375176 non-null float64 id              375176 non-null int64 food            375176 non-null object fgroup          375176 non-null object manufacturer    293054 non-null object dtypes: float64(1), int64(1), object(6) memory usage: 25.8+ MB In [178]: ndata.iloc[30000] Out[178]: nutrient                                       Glycine nutgroup                                   Amino Acids units                                                g value                                             0.04 id                                                6158 food            Soup, tomato bisque, canned, condensed fgroup                      Soups, Sauces, and Gravies manufacturer                                           Name: 30000, dtype: object

我们现在可以根据食物分类和营养类型画出一张中位值图(如图14-11所示):

In [180]: result = ndata.groupby(['nutrient', 'fgroup'])['value'].quantile(0.5) In [181]: result['Zinc, Zn'].sort_values().plot(kind='barh')


图片14-11 根据营养分类得出的锌中位值


只要稍微动一动脑子,就可以发现各营养成分最为丰富的食物是什么了:

by_nutrient = ndata.groupby(['nutgroup', 'nutrient']) get_maximum = lambda x: x.loc[x.value.idxmax()] get_minimum = lambda x: x.loc[x.value.idxmin()] max_foods = by_nutrient.apply(get_maximum)[['value', 'food']] # make the food a little smaller max_foods.food = max_foods.food.str[:50]

由于得到的DataFrame很大,所以不方便在书里面全部打印出来。这里只给出"Amino Acids"营养分组:

In [183]: max_foods.loc['Amino Acids']['food'] Out[183]: nutrient Alanine                          Gelatins, dry powder, unsweetened Arginine                              Seeds, sesame flour, low-fat Aspartic acid                                  Soy protein isolate Cystine               Seeds, cottonseed flour, low fat (glandless) Glutamic acid                                  Soy protein isolate                                       ...                         Serine           Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Threonine        Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Tryptophan        Sea lion, Steller, meat with fat (Alaska Native) Tyrosine         Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Valine           Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Name: food, Length: 19, dtype: object

14.5 2012联邦选举委员会数据库


美国联邦选举委员会发布了有关政治竞选赞助方面的数据。其中包括赞助者的姓名、职业、雇主、地址以及出资额等信息。我们对2012年美国总统大选的数据集比较感兴趣(http://www.fec.gov/disclosurep/PDownload.do)。我在2012年6月下载的数据集是一个150MB的CSV文件(P00000001-ALL.csv),我们先用pandas.read_csv将其加载进来:

In [184]: fec = pd.read_csv('datasets/fec/P00000001-ALL.csv') In [185]: fec.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 1001731 entries, 0 to 1001730 Data columns (total 16 columns): cmte_id              1001731 non-null object cand_id              1001731 non-null object cand_nm              1001731 non-null object contbr_nm            1001731 non-null object contbr_city          1001712 non-null object contbr_st            1001727 non-null object contbr_zip           1001620 non-null object contbr_employer      988002 non-null object contbr_occupation    993301 non-null object contb_receipt_amt    1001731 non-null float64 contb_receipt_dt     1001731 non-null object receipt_desc         14166 non-null object memo_cd              92482 non-null object memo_text            97770 non-null object form_tp              1001731 non-null object file_num             1001731 non-null int64 dtypes: float64(1), int64(1), object(14) memory usage: 122.3+ MB

该DataFrame中的记录如下所示:

In [186]: fec.iloc[123456] Out[186]: cmte_id             C00431445 cand_id             P80003338 cand_nm         Obama, Barack contbr_nm         ELLMAN, IRA contbr_city             TEMPE                    ...       receipt_desc              NaN memo_cd                   NaN memo_text                 NaN form_tp                 SA17A file_num               772372 Name: 123456, Length: 16, dtype: object

你可能已经想出了许多办法从这些竞选赞助数据中抽取有关赞助人和赞助模式的统计信息。我将在接下来的内容中介绍几种不同的分析工作(运用到目前为止已经学到的方法)。


不难看出,该数据中没有党派信息,因此最好把它加进去。通过unique,你可以获取全部的候选人名单:

In [187]: unique_cands = fec.cand_nm.unique() In [188]: unique_cands Out[188]: array(['Bachmann, Michelle', 'Romney, Mitt', 'Obama, Barack',       "Roemer, Charles E. 'Buddy' III", 'Pawlenty, Timothy',       'Johnson, Gary Earl', 'Paul, Ron', 'Santorum, Rick', 'Cain, Herman',       'Gingrich, Newt', 'McCotter, Thaddeus G', 'Huntsman, Jon',       'Perry, Rick'], dtype=object) In [189]: unique_cands[2] Out[189]: 'Obama, Barack'

指明党派信息的方法之一是使用字典:

parties = {'Bachmann, Michelle': 'Republican',           'Cain, Herman': 'Republican',           'Gingrich, Newt': 'Republican',           'Huntsman, Jon': 'Republican',           'Johnson, Gary Earl': 'Republican',           'McCotter, Thaddeus G': 'Republican',           'Obama, Barack': 'Democrat',           'Paul, Ron': 'Republican',           'Pawlenty, Timothy': 'Republican',           'Perry, Rick': 'Republican',           "Roemer, Charles E. 'Buddy' III": 'Republican',           'Romney, Mitt': 'Republican',           'Santorum, Rick': 'Republican'}

现在,通过这个映射以及Series对象的map方法,你可以根据候选人姓名得到一组党派信息:

In [191]: fec.cand_nm[123456:123461] Out[191]: 123456    Obama, Barack 123457    Obama, Barack 123458    Obama, Barack 123459    Obama, Barack 123460    Obama, Barack Name: cand_nm, dtype: object In [192]: fec.cand_nm[123456:123461].map(parties) Out[192]: 123456    Democrat 123457    Democrat 123458    Democrat 123459    Democrat 123460    Democrat Name: cand_nm, dtype: object # Add it as a column In [193]: fec['party'] = fec.cand_nm.map(parties) In [194]: fec['party'].value_counts() Out[194]: Democrat      593746 Republican    407985 Name: party, dtype: int64

这里有两个需要注意的地方。第一,该数据既包括赞助也包括退款(负的出资额):

In [195]: (fec.contb_receipt_amt > 0).value_counts() Out[195]: True     991475 False     10256 Name: contb_receipt_amt, dtype: int64

为了简化分析过程,我限定该数据集只能有正的出资额:

In [196]: fec = fec[fec.contb_receipt_amt > 0]

由于Barack Obama和Mitt Romney是最主要的两名候选人,所以我还专门准备了一个子集,只包含针对他们两人的竞选活动的赞助信息:

In [197]: fec_mrbo = fec[fec.cand_nm.isin(['Obama, Barack','Romney, Mitt'])]

根据职业和雇主统计赞助信息


基于职业的赞助信息统计是另一种经常被研究的统计任务。例如,律师们更倾向于资助民主党,而企业主则更倾向于资助共和党。你可以不相信我,自己看那些数据就知道了。首先,根据职业计算出资总额,这很简单:

In [198]: fec.contbr_occupation.value_counts()[:10] Out[198]: RETIRED                                   233990 INFORMATION REQUESTED                      35107 ATTORNEY                                   34286 HOMEMAKER                                  29931 PHYSICIAN                                  23432 INFORMATION REQUESTED PER BEST EFFORTS     21138 ENGINEER                                   14334 TEACHER                                    13990 CONSULTANT                                 13273 PROFESSOR                                  12555 Name: contbr_occupation, dtype: int64

不难看出,许多职业都涉及相同的基本工作类型,或者同一样东西有多种变体。下面的代码片段可以清理一些这样的数据(将一个职业信息映射到另一个)。注意,这里巧妙地利用了dict.get,它允许没有映射关系的职业也能“通过”:

occ_mapping = {   'INFORMATION REQUESTED PER BEST EFFORTS' : 'NOT PROVIDED',   'INFORMATION REQUESTED' : 'NOT PROVIDED',   'INFORMATION REQUESTED (BEST EFFORTS)' : 'NOT PROVIDED',   'C.E.O.': 'CEO' } # If no mapping provided, return x f = lambda x: occ_mapping.get(x, x) fec.contbr_occupation = fec.contbr_occupation.map(f)

我对雇主信息也进行了同样的处理:

emp_mapping = {   'INFORMATION REQUESTED PER BEST EFFORTS' : 'NOT PROVIDED',   'INFORMATION REQUESTED' : 'NOT PROVIDED',   'SELF' : 'SELF-EMPLOYED',   'SELF EMPLOYED' : 'SELF-EMPLOYED', } # If no mapping provided, return x f = lambda x: emp_mapping.get(x, x) fec.contbr_employer = fec.contbr_employer.map(f)

现在,你可以通过pivot_table根据党派和职业对数据进行聚合,然后过滤掉总出资额不足200万美元的数据:

In [201]: by_occupation = fec.pivot_table('contb_receipt_amt',   .....:                                 index='contbr_occupation',   .....:                                 columns='party', aggfunc='sum') In [202]: over_2mm = by_occupation[by_occupation.sum(1) > 2000000] In [203]: over_2mm Out[203]: party                 Democrat    Republican contbr_occupation                           ATTORNEY           11141982.97  7.477194e+06 CEO                 2074974.79  4.211041e+06 CONSULTANT          2459912.71  2.544725e+06 ENGINEER             951525.55  1.818374e+06 EXECUTIVE           1355161.05  4.138850e+06 ...                        ...           ... PRESIDENT           1878509.95  4.720924e+06 PROFESSOR           2165071.08  2.967027e+05 REAL ESTATE          528902.09  1.625902e+06 RETIRED            25305116.38  2.356124e+07 SELF-EMPLOYED        672393.40  1.640253e+06 [17 rows x 2 columns]

把这些数据做成柱状图看起来会更加清楚('barh'表示水平柱状图,如图14-12所示):

In [205]: over_2mm.plot(kind='barh')

图14-12 对各党派总出资额最高的职业


你可能还想了解一下对Obama和Romney总出资额最高的职业和企业。为此,我们先对候选人进行分组,然后使用本章前面介绍的类似top的方法:

def get_top_amounts(group, key, n=5):    totals = group.groupby(key)['contb_receipt_amt'].sum()    return totals.nlargest(n)

然后根据职业和雇主进行聚合:

In [207]: grouped = fec_mrbo.groupby('cand_nm') In [208]: grouped.apply(get_top_amounts, 'contbr_occupation', n=7) Out[208]: cand_nm        contbr_occupation     Obama, Barack  RETIRED                  25305116.38               ATTORNEY                 11141982.97               INFORMATION REQUESTED     4866973.96               HOMEMAKER                 4248875.80               PHYSICIAN                 3735124.94                                           ...     Romney, Mitt   HOMEMAKER                 8147446.22               ATTORNEY                  5364718.82               PRESIDENT                 2491244.89               EXECUTIVE                 2300947.03               C.E.O.                    1968386.11 Name: contb_receipt_amt, Length: 14, dtype: float64 In [209]: grouped.apply(get_top_amounts, 'contbr_employer', n=10) Out[209]: cand_nm        contbr_employer       Obama, Barack  RETIRED                  22694358.85               SELF-EMPLOYED            17080985.96               NOT EMPLOYED              8586308.70               INFORMATION REQUESTED     5053480.37               HOMEMAKER                 2605408.54                                           ...     Romney, Mitt   CREDIT SUISSE              281150.00               MORGAN STANLEY             267266.00               GOLDMAN SACH & CO.         238250.00               BARCLAYS CAPITAL           162750.00               H.I.G. CAPITAL             139500.00 Name: contb_receipt_amt, Length: 20, dtype: float64

对出资额分组


还可以对该数据做另一种非常实用的分析:利用cut函数根据出资额的大小将数据离散化到多个面元中:

In [210]: bins = np.array([0, 1, 10, 100, 1000, 10000,   .....:                  100000, 1000000, 10000000]) In [211]: labels = pd.cut(fec_mrbo.contb_receipt_amt, bins) In [212]: labels Out[212]: 411         (10, 100] 412       (100, 1000] 413       (100, 1000] 414         (10, 100] 415         (10, 100]             ...     701381      (10, 100] 701382    (100, 1000] 701383        (1, 10] 701384      (10, 100] 701385    (100, 1000] Name: contb_receipt_amt, Length: 694282, dtype: category Categories (8, interval[int64]): [(0, 1] < (1, 10] < (10, 100] < (100, 1000] < (1 000, 10000] <                                  (10000, 100000] < (100000, 1000000] < (1000000, 10000000]]

现在可以根据候选人姓名以及面元标签对奥巴马和罗姆尼数据进行分组,以得到一个柱状图:

In [213]: grouped = fec_mrbo.groupby(['cand_nm', labels]) In [214]: grouped.size().unstack(0) Out[214]: cand_nm              Obama, Barack  Romney, Mitt contb_receipt_amt                               (0, 1]                       493.0          77.0 (1, 10]                    40070.0        3681.0 (10, 100]                 372280.0       31853.0 (100, 1000]               153991.0       43357.0 (1000, 10000]              22284.0       26186.0 (10000, 100000]                2.0           1.0 (100000, 1000000]              3.0           NaN (1000000, 10000000]            4.0           NaN

从这个数据中可以看出,在小额赞助方面,Obama获得的数量比Romney多得多。你还可以对出资额求和并在面元内规格化,以便图形化显示两位候选人各种赞助额度的比例(见图14-13):

In [216]: bucket_sums = grouped.contb_receipt_amt.sum().unstack(0) In [217]: normed_sums = bucket_sums.div(bucket_sums.sum(axis=1), axis=0) In [218]: normed_sums Out[218]: cand_nm              Obama, Barack  Romney, Mitt contb_receipt_amt                               (0, 1]                    0.805182      0.194818 (1, 10]                   0.918767      0.081233 (10, 100]                 0.910769      0.089231 (100, 1000]               0.710176      0.289824 (1000, 10000]             0.447326      0.552674 (10000, 100000]           0.823120      0.176880 (100000, 1000000]         1.000000           NaN (1000000, 10000000]       1.000000           NaN In [219]: normed_sums[:-2].plot(kind='barh')

图14-13 两位候选人收到的各种捐赠额度的总额比例


我排除了两个最大的面元,因为这些不是由个人捐赠的。


还可以对该分析过程做许多的提炼和改进。比如说,可以根据赞助人的姓名和邮编对数据进行聚合,以便找出哪些人进行了多次小额捐款,哪些人又进行了一次或多次大额捐款。我强烈建议你下载这些数据并自己摸索一下。


根据州统计赞助信息


根据候选人和州对数据进行聚合是常规操作:

In [220]: grouped = fec_mrbo.groupby(['cand_nm', 'contbr_st']) In [221]: totals = grouped.contb_receipt_amt.sum().unstack(0).fillna(0) In [222]: totals = totals[totals.sum(1) > 100000] In [223]: totals[:10] Out[223]: cand_nm    Obama, Barack  Romney, Mitt contbr_st                             AK             281840.15      86204.24 AL             543123.48     527303.51 AR             359247.28     105556.00 AZ            1506476.98    1888436.23 CA           23824984.24   11237636.60 CO            2132429.49    1506714.12 CT            2068291.26    3499475.45 DC            4373538.80    1025137.50 DE             336669.14      82712.00 FL            7318178.58    8338458.81

如果对各行除以总赞助额,就会得到各候选人在各州的总赞助额比例:

In [224]: percent = totals.div(totals.sum(1), axis=0) In [225]: percent[:10] Out[225]: cand_nm    Obama, Barack  Romney, Mitt contbr_st                             AK              0.765778      0.234222 AL              0.507390      0.492610 AR              0.772902      0.227098 AZ              0.443745      0.556255 CA              0.679498      0.320502 CO              0.585970      0.414030 CT              0.371476      0.628524 DC              0.810113      0.189887 DE              0.802776      0.197224 FL              0.467417      0.532583

14.6 总结


我们已经完成了正文的最后一章。附录中有一些额外的内容,可能对你有用。

本书第一版出版已经有5年了,Python已经成为了一个流行的、广泛使用的数据分析语言。你从本书中学到的方法,在相当长的一段时间都是可用的。我希望本书介绍的工具和库对你的工作有用。


最后4小时优惠价,扫码立即学习

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存